﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MapEditor
{
    class Data
    {
        //public int RealMapWidth = 0;
        private int Height_Load = 0;
        private int Width_Load = 0;
        List<GameObject> _ObjectList = new List<GameObject>();
        public List<GameObject> ObjectList
        {
            get { return _ObjectList; }
        }
        public void InitDefaultMap()
        {
            _ObjectList.Clear();
            GameObject.ResetStaticID();
        }

        //location: center
        public bool ApplyValue(Point location, int value, bool isUpperLayer)
        {

            Size tempSize = GameObject.ObjectDimension(value);
            if (!isInMap(location, tempSize))
            {
                MessageBox.Show("Object must be in Map");
                return false;
            }
            Point tempUpperPoint = GameObject.ConvertToUpperPoint(location, tempSize);
            if (isUpperLayer)
            {
                if (isOverwriten(location, tempSize))
                {
                    MessageBox.Show("Can not over draw");
                    return false;
                }
                else
                {
                    _ObjectList.Add(new GameObject(value, new Rectangle(tempUpperPoint, tempSize)));
                    return true;
                }
            }
            else
            {
                _ObjectList.Add(new GameObject(value, new Rectangle(tempUpperPoint, tempSize)));
                return true;
            }
        }

        public void ShowDetail(Point mouseLocation, bool isUpperLayer, out int ID, out string type, out Point position, out Size dimension)
        {
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                if (mouseLocation.X >= _ObjectList[i].XUpper && mouseLocation.X < _ObjectList[i].XUpper + _ObjectList[i].Width &&
                    mouseLocation.Y >= _ObjectList[i].YUpper && mouseLocation.Y < _ObjectList[i].YUpper + _ObjectList[i].Height)
                {
                    if (_ObjectList[i].IsUpperItem == isUpperLayer)
                    {
                        ID = _ObjectList[i].ID;

                        int tempType = _ObjectList[i].ItemIndex;
                        switch (tempType)
                        {
                            case 0: type = "Mario"; break;
                            default: type = "Normal Brick"; ; break;
                            case 2: type = "Red Mushroom"; ; break;
                            case 3: type = "Green Mushroom"; break;
                            case 4: type = "Hard Brick"; break;
                            case 5: type = "Grass"; break;
                            case 7: type = "Goomba"; break;
                            case 8: type = "Turtle"; break;

                            case 100: type = "Tree"; break;
                            case 101: type = "Flower"; break;
                            case 102: type = "Cloud"; break;
                        }

                        position = new Point(_ObjectList[i].XUpper, _ObjectList[i].YUpper);
                        dimension = new Size(_ObjectList[i].Width, _ObjectList[i].Height);
                        return;
                    }
                }
            }
            ID = -1;
            type = " ";
            position = mouseLocation;
            dimension = new Size(-1, -1);
        }

        //Calculate bound world and flip y for all game objects
        public Rectangle GameBound()
        {
            if (_ObjectList.Count > 0)
            {
                int minX, maxX, minY, maxY;
                Calculation(out minX, out maxX, out minY, out maxY);
                //Get dimension
                maxX -= minX;
                maxY -= minY;

                //Get max of width and height
                int max = maxX;
                if (maxY > max) max = maxY;

                //mapWidh must be >= 720
                if (max < 720) max = 720;

                //Calculate real width
                //RealMapWidth = max;

                //Move game objects
                for (int i = 0; i < _ObjectList.Count; ++i)
                {
                    _ObjectList[i].XUpper -= minX;
                    _ObjectList[i].YUpper -= minY;
                }
                max = (int)Util.SmallestPowerOfTwo(max);
                FlipY();
                return new Rectangle(0, 0, max, max);
            }
            return new Rectangle(0, 0, 0, 0);
        }

        public void RemoveOutObjs(int width, int height)
        {
            for (int i = 0; i < _ObjectList.Count; )
            {
                int a, b;
                a = _ObjectList[i].XUpper + _ObjectList[i].Width;
                b = _ObjectList[i].YUpper + _ObjectList[i].Height;

                if (a > width)
                {
                    _ObjectList.RemoveAt(i);
                    --i;
                    return;
                }
                if (b > height)
                {
                    _ObjectList.RemoveAt(i);
                    --i;
                    return;
                }
                ++i;
            }
        }
        public int CountPlayer()
        {
            int countMario = 0;
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                if (_ObjectList[i].ItemIndex == Config.code_mario)
                    ++countMario;
            }
            return countMario;
        }

        public void ClearValue(Point location, bool isUpperLayer)
        {
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                if (location.X >= _ObjectList[i].XUpper && location.X < _ObjectList[i].XUpper + _ObjectList[i].Width &&
                    location.Y >= _ObjectList[i].YUpper && location.Y < _ObjectList[i].YUpper + _ObjectList[i].Height)
                {
                    if (_ObjectList[i].IsUpperItem == isUpperLayer)
                        _ObjectList.RemoveAt(i);
                }
            }
        }
        public void Clear_UpperMap()
        {
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                _ObjectList.RemoveAll(x => x.IsUpperItem == true);
            }
        }
        public void Clear_LowerMap()
        {
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                _ObjectList.RemoveAll(x => x.IsUpperItem == false);
            }
        }

        public void LoadFile(string fileName)
        {
            StreamReader sr = new StreamReader(fileName);
            string content = sr.ReadToEnd();
            string[] lines = content.Split('\n');
            InitDefaultMap();

            //lines[length - 1] = " ". 
            for (int i = 0; i < lines.Length - 1; ++i)
            {
                string[] bits = lines[i].Split(' ');
                //first line stores MapDimensionMax
                if (i == 0)
                {
                    Width_Load = int.Parse(bits[0].ToString());
                    Height_Load = int.Parse(bits[1].ToString());
                    Config.Map_W = Width_Load;
                    Config.Map_H = Height_Load;
                }
                else
                {
                    int type = int.Parse(bits[1]);

                    int xCenter = int.Parse(bits[2]), yCenter = int.Parse(bits[3]);
                    Size size = GameObject.ObjectDimension(type);
                    //convert to Y up
                    yCenter = Height_Load - yCenter;
                    Point pos = GameObject.ConvertToUpperPoint(new Point(xCenter, yCenter), size);

                    _ObjectList.Add(new GameObject(type, new Rectangle(pos, size)));
                }
            }
            sr.Close();
        }
        public void SaveObjectFile(string fileGameObj)
        {
            List<int> tempIDList = new List<int>();
            List<string> objList = new List<string>();

            foreach (GameObject o in _ObjectList)
            {
                bool exist = false;
                foreach (var i in tempIDList)
                {
                    if (o.ID == i)
                    {
                        exist = true;
                        break;
                    }
                }
                if (!exist)
                {
                    tempIDList.Add(o.ID);
                    objList.Add(o.ToString());
                }
            }
            StreamWriter swObj = new StreamWriter(fileGameObj);
            swObj.WriteLine(GetMapWidth().ToString() + " " + GetMapHeight().ToString());
            foreach (var item in objList)
                swObj.WriteLine(item);
            swObj.Close();
        }

        //location: center
        private bool isOverwriten(Point location, Size size)
        {
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                if (_ObjectList[i].IsUpperItem)
                {
                    Point other_point = new Point(_ObjectList[i].XUpper, _ObjectList[i].YUpper);
                    Size other_size = new Size(_ObjectList[i].Width, _ObjectList[i].Height);

                    Point thisPoint = GameObject.ConvertToUpperPoint(location, size);

                    Rectangle rec1 = new Rectangle(thisPoint, size);
                    Rectangle rec2 = new Rectangle(other_point, other_size);
                    if (rec1.IntersectsWith(rec2)) return true;
                }
            }
            return false;
        }
        //location: center
        private bool isInMap(Point location, Size size)
        {
            Point upperPoint = GameObject.ConvertToUpperPoint(location, size);
            Point lowerPoint = new Point(upperPoint.X + size.Width, upperPoint.Y + size.Height);
            if (upperPoint.X < 0 || upperPoint.Y < 0) return false;
            if (lowerPoint.X > Config.Map_W || lowerPoint.Y > Config.Map_H) return false;
            return true;
        }

        private int GetMapHeight()
        {
            if (_ObjectList.Count > 0)
            {
                int minX, maxX, minY, maxY;
                Calculation(out minX, out maxX, out minY, out maxY);
                return maxY;
            }
            else return 0;
        }
        private int GetMapWidth()
        {
            if (_ObjectList.Count > 0)
            {
                int minX, maxX, minY, maxY;
                Calculation(out minX, out maxX, out minY, out maxY);
                return maxX;
            }
            else return 0;
        }
        private void Calculation(out int minX, out int maxX, out int minY, out int maxY)
        {
            minX = _ObjectList[0].XUpper;
            minY = _ObjectList[0].YUpper;
            maxX = minX + _ObjectList[0].Width;
            maxY = minY + _ObjectList[0].Height;
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                if (_ObjectList[i].XUpper < minX) minX = _ObjectList[i].XUpper;
                if (_ObjectList[i].XUpper + _ObjectList[i].Width > maxX)
                {
                    maxX = _ObjectList[i].XUpper + _ObjectList[i].Width;
                }
                if (_ObjectList[i].YUpper < minY) minY = _ObjectList[i].YUpper;
                if (_ObjectList[i].YUpper + _ObjectList[i].Height > maxY)
                {
                    maxY = _ObjectList[i].YUpper + _ObjectList[i].Height;
                }
            }
        }
        private void FlipY()
        {
            for (int i = 0; i < _ObjectList.Count; ++i)
            {
                _ObjectList[i].CenterPosition = new Point(_ObjectList[i].CenterPosition.X, GetMapHeight() - _ObjectList[i].CenterPosition.Y);
            }
        }
    }
}
